package com.threegroup.admin.annotation.AuthorityVerify;

import com.threegroup.admin.security.user.SecurityUser;
import com.threegroup.common.exception.ErrorCode;
import com.threegroup.common.exception.TakeOutException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 权限校验 切面实现
 */
@Aspect
@Component
@Slf4j
public class AuthorityVerifyAspect {

    private static AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Pointcut(value = "@annotation(authorityVerify)")
    public void pointcut(AuthorityVerify authorityVerify) {

    }

    @Around(value = "pointcut(authorityVerify)")
    public Object doAround(ProceedingJoinPoint joinPoint, AuthorityVerify authorityVerify) throws Throwable {

        ServletRequestAttributes attribute = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attribute.getRequest();
        //获取请求路径
        String url = request.getRequestURI();
        SecurityUser securityUser = (SecurityUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        // 管理员拥有的权限
        List<SimpleGrantedAuthority> authorities = (List<SimpleGrantedAuthority>) securityUser.getAuthorities();
        String permission = authorityVerify.value();

        boolean contains = authorities.stream()
                .map(SimpleGrantedAuthority::getAuthority)
                .anyMatch(a -> antPathMatcher.match(a, permission));

        // 判断该角色是否能够访问该接口
        if (contains) {
            log.info("用户拥有操作权限，访问的路径: {}，拥有的权限接口：{}", url, permission);
            //执行业务
            return joinPoint.proceed();
        } else {
            log.info("用户不具有操作权限，访问的路径: {}", url);
            throw new TakeOutException(ErrorCode.UNAUTHORIZED, "权限不足，请联系管理员");
        }
    }
}
